// =======================================================================================
/*!
 * @file    Uninstall.c
 *
 * @brief   Uninstall Application.
 *
 * This program activates the MSIEXEC uninstall procedure for the specified GUID.
 *
 * @author  Jorge Ramos (jramos at pobox dot com).
 *
 * @version 1.0.0.0 - Apr 10, 2011
 *          @li Initial version.
 *
 * @remarks Copyright (c) 2011 Jorge Ramos.
 *
 * @remarks This software is provided 'as-is', without any express or implied warranty.
 *          Use it at your own risk. In no event shall the authors or copyright holders
 *          be held liable for any damages arising from the use of this software. Use
 *          and redistribution in source and binary forms, with or without modification,
 *          are permitted. Altered source versions must be plainly marked as such.
 *
 * @remarks This software is distributed in the hope that it will be useful, but WITHOUT
 *          ANY WARRANTY.
 */
// =======================================================================================

//////////////////////////////////////////////////////////////////////////////////////////

#ifdef _UNICODE
#ifndef UNICODE
#define UNICODE
#endif
#endif

#ifdef _MSC_VER
#pragma warning (disable: 4115)     /* named type definition in parentheses */
#pragma warning (disable: 4127)     /* conditional expression is constant */
#pragma warning (disable: 4201)     /* nonstandard extension used : nameless struct/union */
#pragma warning (disable: 4505)     /* unreferenced local function has been removed */
#pragma warning (disable: 4514)     /* unreferenced inline function has been removed */
#pragma warning (disable: 4702)     /* unreachable code */
#endif

#ifndef STRICT
#define STRICT                      /* Enable STRICT type checking. */
#endif

#include <stdio.h>
#include <windows.h>
#include <tchar.h>

//////////////////////////////////////////////////////////////////////////////////////////

#ifndef _countof
#define _countof(array) (sizeof (array) / sizeof (array [0]))
#endif

#ifndef UNREFERENCED_PARAMETER
#define UNREFERENCED_PARAMETER(p) ((VOID) (p))
#endif

const TCHAR szApplicationName [] = _T ("Uninstall");

//////////////////////////////////////////////////////////////////////////////////////////

VOID DisplayError (DWORD dwErrorCode)
{
    static const TCHAR szDefaultWin32Message [] = _T ("Win32 Error 0x%08lX (%ld)");
    static const DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS;

    TCHAR szBuffer [128];

    LPTSTR pszMessage = NULL;
    DWORD dwLength = FormatMessage (dwFlags, NULL, dwErrorCode, 0, (LPTSTR) &pszMessage, 0, NULL);

    if (pszMessage != NULL)
    {
        if (dwLength > 0)
        {
            (VOID) MessageBox (NULL, pszMessage, szApplicationName, MB_OK|MB_ICONSTOP);
        }
        else
        {
            (VOID) _sntprintf (szBuffer, _countof (szBuffer), szDefaultWin32Message, dwErrorCode, dwErrorCode);
            (VOID) MessageBox (NULL, szBuffer, szApplicationName, MB_OK|MB_ICONSTOP);
        }

        LocalFree (pszMessage);
    }
    else
    {
        (VOID) _sntprintf (szBuffer, _countof (szBuffer), szDefaultWin32Message, dwErrorCode, dwErrorCode);
        (VOID) MessageBox (NULL, szBuffer, szApplicationName, MB_OK|MB_ICONSTOP);
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

INT APIENTRY _tWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR pszCmdLine, INT nCmdShow)
{
    SECURITY_ATTRIBUTES sa;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    TCHAR szCommandLine [128];
    INT nChars;

    UNREFERENCED_PARAMETER (hInstance);
    UNREFERENCED_PARAMETER (hPrevInstance);
    UNREFERENCED_PARAMETER (nCmdShow);

    // Format the command line.

    nChars = _sntprintf (szCommandLine, _countof (szCommandLine), _T ("msiexec.exe /x %s"), pszCmdLine);

    if (nChars < 0 || nChars >= _countof (szCommandLine))
    {
        DisplayError (ERROR_INSUFFICIENT_BUFFER);
        return 3;
    }

    // Start the child process.

    ZeroMemory (&sa, sizeof (sa)); sa.nLength = sizeof (sa);
    ZeroMemory (&si, sizeof (si)); si.cb = sizeof(si);
    ZeroMemory (&pi, sizeof (pi));

    if (! CreateProcess (NULL, szCommandLine, &sa, &sa, TRUE, 0, NULL, NULL,  &si, &pi))
    {
        DisplayError (GetLastError ());
        return 3;
    }

    // Close process and thread handles. 

    CloseHandle (pi.hProcess);
    CloseHandle (pi.hThread);

    // Exit successfully.

    return 0;
}
